/*
此例子说明接口定义和接口使用。
1. 接口不需要明确的在实际类型中之名。
2. 判断一个类型是否实现了接口，需要要
	看类型中是否实现了接口中定义的所有方法。
3. 如果两个接口定义了相同的方法，那么某个类型也实现了所有的方法，这个类型可以说是实现了两个接口。
4. 判断是否一个类型实现了所有接口可以被类型检查系统直接察觉到。
*/

package interfaces

import (
	"fmt"
	"math"
	"strconv"
)

type geometry interface {
	area() float64
	perim() float64
}

type geometric interface {
	area() float64
	perim() float64
	descript() string
}

type rect struct {
	width, height float64
}
type circle struct {
	radius float64
}

type triangle struct {
	a float64
	b float64
	c float64
}

func (r rect) area() float64 {
	return r.width * r.height
}

func (r rect) perim() float64 {
	return 2*r.width + 2*r.height
}

func (c circle) area() float64 {
	return math.Pi * c.radius * c.radius
}

func (c circle) perim() float64 {
	return 2 * math.Pi * c.radius
}

func (t triangle) area() float64 {

	p := (t.a + t.b + t.c) / 2
	return math.Sqrt(p * (p - t.a) * (p - t.b) * (p - t.c))
}

func (t triangle) perim() float64 {
	return t.a + t.b + t.c
}

func (t triangle) descript() string {

	return "Triangle area is " + strconv.FormatFloat(t.area(), 'f', 1, 64) + " and perim is " + strconv.FormatFloat(t.perim(), 'f', 1, 64)
}

func measure(g geometry) {
	fmt.Println(g)
	fmt.Println(g.area())
	fmt.Println(g.perim())
}

func meansureForGeometric(g geometric) {
	fmt.Println(g)
	fmt.Println(g.area())
	fmt.Println(g.descript())

}

func MakeInterface() {
	r := rect{width: 3, height: 4}
	c := circle{radius: 5}
	t := triangle{a: 3, b: 4, c: 5}
	measure(r)
	measure(c)
	//以下代码将报错，应为rect未定义Geometric中定义的descript
	//meansureForGeometric(r)
	meansureForGeometric(t)
}
